Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make Client object globally available #1043

Merged
merged 6 commits into from
Mar 1, 2021
Merged

Conversation

basepi
Copy link
Contributor

@basepi basepi commented Feb 10, 2021

What does this pull request do?

Managing the Client object has always been a bit of a pain. Most of the time passing around the Client via the framework's application objects works ok. But as we move into supporting more instrumentations that require creating transactions (like Kafka), getting the client object becomes more of a pain.

The idea behind this (unfinished) PR is to painlessly save the Client object when it is created, and provide elasticapm.get_client() to make it easy to get that Client object from anywhere.

If we decide this is a good idea, the next step is to remove all of the framework-specific scaffolding around the Client object and use this new elasticapm.get_client() everywhere.

@beniwohli thoughts?

@apmmachine
Copy link
Contributor

apmmachine commented Feb 10, 2021

💚 Build Succeeded

the below badges are clickable and redirect to their specific view in the CI or DOCS
Pipeline View Test View Changes Artifacts preview

Expand to view the summary

Build stats

  • Build Cause: Started by user Colton Myers

  • Start Time: 2021-03-01T17:21:40.239+0000

  • Duration: 22 min 59 sec

  • Commit: be9abfa

Test stats 🧪

Test Results
Failed 0
Passed 7932
Skipped 5735
Total 13667

Trends 🧪

Image of Build Times

Image of Tests

💚 Flaky test report

Tests succeeded.

Expand to view the summary

Test stats 🧪

Test Results
Failed 0
Passed 7932
Skipped 5735
Total 13667

@beniwohli
Copy link
Contributor

Interesting idea! So far, there is nothing in the agent that would make it impossible to have multiple agent instances running, so we'll have to make sure we don't break any relevant use cases with this.

I think this change would also allow us to tie instrumentation to the agent instance, making it possible to make the list of instrumentations configurable, which would be nice. Not sure how that would interact with the wrapper script that we plan to introduce, though.

Semi-related, looks like we forgot another 6.0 breaking change :( :

else:
# In 6.0, this should raise a ValueError
warnings.warn(
"LoggingHandler requires a Client instance. No Client was "
"received. This will result in an error starting in v6.0 "
"of the agent",
PendingDeprecationWarning,
)
self.client = Client(*args, **kwargs)

@basepi
Copy link
Contributor Author

basepi commented Feb 17, 2021

So far, there is nothing in the agent that would make it impossible to have multiple agent instances running, so we'll have to make sure we don't break any relevant use cases with this.

Do you have any use cases in mind? In the "multiple agent instances" case we end up with separate client instances anyway before this PR, right?

Not sure how that would interact with the wrapper script that we plan to introduce, though.

Luckily we get to write the wrapper script so I don't expect it to be a problem. :)

@basepi basepi marked this pull request as ready for review February 25, 2021 18:25
@basepi
Copy link
Contributor Author

basepi commented Feb 25, 2021

I realized that I don't really need to change every instance of self.client and app.client to get_client() -- but I did do a little cleanup in some places to use the new system (especially in Django land where we were already using globals to store the Client object).

I can't think of any other places that will be hit adversely by this change, so I think this is ready for review.

Comment on lines -514 to -524
def test_get_client(django_elasticapm_client):
with mock.patch.dict("os.environ", {"ELASTIC_APM_METRICS_INTERVAL": "0ms"}):
client2 = get_client("elasticapm.base.Client")
try:
assert get_client() is get_client()
assert client2.__class__ == Client
finally:
get_client().close()
client2.close()


Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Django's get_client() is only ever called with an argument here, in this test. Thus, I don't think we need the type-checking functionality that was in the old implementation. I just removed the test.

Copy link
Contributor

@beniwohli beniwohli left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lots of simplifications,I like!

@basepi basepi merged commit 74fe1e8 into elastic:master Mar 1, 2021
@basepi basepi changed the title [WIP] Make Client object globally available Make Client object globally available Mar 10, 2021
@DougDK
Copy link
Contributor

DougDK commented Apr 13, 2021

Interesting idea! So far, there is nothing in the agent that would make it impossible to have multiple agent instances running, so we'll have to make sure we don't break any relevant use cases with this.

I think this change would also allow us to tie instrumentation to the agent instance, making it possible to make the list of instrumentations configurable, which would be nice. Not sure how that would interact with the wrapper script that we plan to introduce, though.

Semi-related, looks like we forgot another 6.0 breaking change :( :

else:
# In 6.0, this should raise a ValueError
warnings.warn(
"LoggingHandler requires a Client instance. No Client was "
"received. This will result in an error starting in v6.0 "
"of the agent",
PendingDeprecationWarning,
)
self.client = Client(*args, **kwargs)

It looks like there's a use case that this would break. I create an issue for it to investigate a possible bug.
Issue 1098

beniwohli pushed a commit to beniwohli/apm-agent-python that referenced this pull request Sep 14, 2021
* Make Client object globally available

* Remove global client object on Client.close()

* Fix django's get_client to use elasticapm.get_client

* Clean up more client creation

* CHANGELOG
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants